package com.cat.conf.spi;

import com.google.common.collect.Maps;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Map;

/**
 * 自定义SPI装配，为标记为{@link com.cat.conf.spi.WhiskySPI}的接口保留唯一在user.factory指定的实现，将其他的bean都移除
 *
 * @author xiemh
 * @date 2019/1/30 9:55
 * @since v1.0.0
 */
public class SpiPostProcessor implements BeanDefinitionRegistryPostProcessor, BeanFactoryAware {

    private static final String FACTORY_URL = "META-INF/yytech/user.factory";
    private ListableBeanFactory factory;
    private Map<String, String> spiMap = Maps.newHashMap();

    public SpiPostProcessor() {
        initMap();
        // System.out.println(spiMap);
    }

    private void initMap() {
        URL u = ClassLoader.getSystemResource(FACTORY_URL);
        try (InputStream in = u.openStream();
                BufferedReader r = new BufferedReader(new InputStreamReader(in, "utf-8"))) {
            String ln = null;
            while ((ln = r.readLine()) != null) {
                int ci = ln.indexOf('#');
                int equal = ln.indexOf('=');
                if (ci == 0 || equal == -1 || equal >= ln.length() - 1) {
                    System.out.println("warn:本行已注释或格式不合法：" + ln);
                    continue;
                }
                System.out.println("info:用户定义实现注册：" + ln);
                String key = ln.substring(0, equal);
                String value = ln.substring(equal + 1, ln.length());
                spiMap.put(key, value);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.factory = (ListableBeanFactory) beanFactory;
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        Map<String, Object> SpiBeans = factory.getBeansWithAnnotation(WhiskySPI.class);

        for (String beanName : SpiBeans.keySet()) {
            Class<?> beanClass = SpiBeans.get(beanName).getClass();
            Class<?>[] interfaces = beanClass.getInterfaces();
            for (Class<?> clazz : interfaces) {
                String chosenBean = spiMap.get(clazz.getName());
                if (!StringUtils.isEmpty(chosenBean) && !chosenBean.equals(beanClass.getName())) {
                    registry.removeBeanDefinition(beanName);
                    System.out.println("成功移除bean:"+beanName);
                }
            }
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }

}
